#ifndef	ACL_FHANDLE_INCLUDE_H
#define	ACL_FHANDLE_INCLUDE_H

#ifdef	__cplusplus
extern "C" {
#endif

#include "acl_define.h"
#include "acl_vstream.h"
#include "acl_vstring.h"
#include "acl_ring.h"
#include "../thread/acl_thread.h"
#include <time.h>

/**
 * 通用的存储文件句柄对象类型定义
 */
typedef struct ACL_FHANDLE ACL_FHANDLE;

struct ACL_FHANDLE {
	ACL_VSTREAM *fp;                          // 存储文件句柄
	acl_int64 fsize;                          // 存储文件大小
	int nrefer;                               // 该存储句柄被引用的计数值
	acl_pthread_mutex_t mutex;                // 线程锁
#if defined(_WIN32) || defined(_WIN64)
	unsigned long tid; // 打开该存储的线程号
	unsigned long lock_mutex_tid; // 加线程锁的线程号
#else
	acl_pthread_t tid;                        // 打开该存储的线程号
	acl_pthread_t lock_mutex_tid;             // 加线程锁的线程号
#endif
	unsigned int oflags;                      // 打开时的标志位
#define	ACL_FHANDLE_O_FLOCK	(1 << 0)	      // 使用文件锁
#define	ACL_FHANDLE_O_MLOCK	(1 << 1)	      // 使用线程锁
#define	ACL_FHANDLE_O_MKDIR	(1 << 2)	      // 是否自动检查并创建不存在的目录
#define	ACL_FHANDLE_O_NOATIME	(1 << 3)	  // 打开文件时添加 O_NOATIME 标志位
#define	ACL_FHANDLE_O_DIRECT	(1 << 4)	  // 打开文件时添加 O_DIRECT 标志位
#define	ACL_FHANDLE_O_SYNC	(1 << 5)	      // 打开文件时添加 O_SYNC 标志位
#define	ACL_FHANDLE_O_EXCL	(1 << 6)	      // 打开文件时是否是自动加锁

	unsigned int status;                      // 该存储文件句柄的状态
#define	ACL_FHANDLE_S_FLOCK_ON	(1 << 0)	  // 该存储句柄已经加文件锁
#define	ACL_FHANDLE_S_MUTEX_ON	(1 << 1)	  // 该存储句柄已经加线程锁

	time_t when_free;                         // 在延迟关闭缓存队列中存活的时间截
	ACL_RING ring;                            // 缓存数据结点
	size_t size;                              // 该 ACL_FHANDLE 对象的实际大小 >= sizeof(ACL_FHANDLE)
	void (*on_close)(ACL_FHANDLE*);           // 当该文件缓存句柄真正关闭时的回调函数，可以为空
};

#define	ACL_FHANDLE_PATH(x)	(ACL_VSTREAM_PATH((x)->fp))

/**
 * 初始化文件句柄操作，该函数须在程序运行初始化时被调用且只能被调用一次
 * @param cache_size {int} 内部被打开文件句柄的最大个数
 * @param debug_section {int} 调试级别
 * @param flags {unsigned int}
 */
void acl_fhandle_init(int cache_size, int debug_section, unsigned int flags);
#define	ACL_FHANDLE_F_LOCK	(1 << 0)

/**
 * 当程序退出时需要调用此函数来释放系统资源
 */
void acl_fhandle_end(void);

/**
 * 打开一个文件
 * @param size {size_t} 分配结构 FS_HANDDLE 需要的空间大小
 * @param oflags {unsigned int} 打开文件句柄时的标志位, ACL_FHANDLE_O_XXX
 * @param file_path {const char*} 文件名(包含路径)
 * @param on_open {int (*)(ACL_FHANDLE*, void*)} 如果不为空，
 *  则当文件句柄被成功打开后便调用此函数
 * @param open_arg {void *} on_open 的回调参数之一
 * @param on_close {void (*)(ACL_FHANDLE*)} 如果不为空，
 *  则当文件句柄被正直关闭时便调用此函数
 */
ACL_FHANDLE *acl_fhandle_open(size_t size, unsigned int oflags,
		const char *file_path, int (*on_open)(ACL_FHANDLE*, void*),
		void *open_arg, void (*on_close)(ACL_FHANDLE*));

/**
 * 关闭一个文件句柄
 * @param fs {ACL_FHANDLE*}
 * @param delay_timeout {int} 如果 > 0, 则延迟该时间后才真正关闭,
 *  否则，其引用计数为 0 则立即关闭
 */
void acl_fhandle_close(ACL_FHANDLE *fs, int delay_timeout);

/**
 * 对一个文件句柄加锁(先加线程锁后加文件锁)
 * @param fs {ACL_FHANDLE*}
 */
void acl_fhandle_lock(ACL_FHANDLE *fs);

/**
 * 对一个文件句柄解锁(先解文件锁再解线程锁)
 * @param fs {ACL_FHANDLE*}
 */
void acl_fhandle_unlock(ACL_FHANDLE *fs);

#ifdef	__cplusplus
}
#endif

#endif
